package service

import (
	"encoding/json"
	"errors"
	"github.com/gin-gonic/gin"
	uuid "github.com/satori/go.uuid"
	"gorm.io/gorm"
	"guns-go/global"
	"guns-go/model"
	"guns-go/model/request"
	"guns-go/model/response"
	"guns-go/utils"
	"strconv"
	"time"
)

//@author: [.zhangr](https://github.com/zqlove001)
//@function: Login
//@description: 用户登录
//@param: u *model.SysUser
//@return: err error, userInter *model.SysUser
func Login(u *model.SysUser) (err error, userInter *model.SysUser) {
	var user model.SysUser
	u.Password = utils.MD5V([]byte(u.Password))
	err = global.GVA_DB.Where("account = ? AND password = ?", u.Account, u.Password).First(&user).Error
	return err, &user
}

func SaveUser(u *model.SysUser, tx *gorm.DB) error {
	return tx.Create(u).Error
}

func UpdateUserById(sysUser *model.SysUser, tx *gorm.DB) error {
	return tx.Model(&sysUser).Updates(sysUser).Error
}

//@author: [q.zhangr](https://github.com/zqlove001)
//@function: UpdateByUserId
//@description: 更新用户IP和登陆时间
//@param: ip string
//@return: err error
func UpdateByUserId(ip string, id int) (err error) {

	sysUser := model.SysUser{
		Id: id,
	}

	updateUser := model.SysUser{
		LastLoginIp:   ip,
		LastLoginTime: time.Now(),
	}
	err = global.GVA_DB.Model(&sysUser).Updates(updateUser).Error
	return err
}

//@author: [.zhangr](https://github.com/zqlove001)
//@function: QueryUserById
//@description: 更加userId查询用户信息
//@param: userId int
//@return: err error,u model.SysUser
func QueryUserById(userId int) (err error, u model.SysUser) {
	var user model.SysUser
	err = global.GVA_DB.Where("id = ?", userId).First(&user).Error
	return err, user
}

//@author: [q.zhangr](https://github.com/zqlove001)
//@function: GetRedisJWT
//@description: 从redis取jwt
//@param: uuid string
//@return: err error, redisJWT string

func GetRedisJWT(uuid uuid.UUID) (err error, redisJWT string) {
	key := uuid.String()
	redisJWT, err = global.GVA_REDIS.HGet("guns:all:users", key).Result()
	return err, redisJWT
}

func GetRedisJWTWithString(gUuid string) (err error, redisJWT string) {
	redisJWT, err = global.GVA_REDIS.HGet("guns:all:users", gUuid).Result()
	return err, redisJWT
}

func GetCacheAllUser() (error, map[string]*model.SysUser) {
	result, err := global.GVA_REDIS.HGetAll("guns:all:users").Result()

	if err != nil {
		return err, nil
	}

	sysUserMap := make(map[string]*model.SysUser, 0)

	if result != nil {
		for key, sysUserStr := range result {
			user := model.SysUser{}
			err = json.Unmarshal([]byte(sysUserStr), &user)

			if err != nil {
				return err, nil
			}

			sysUserMap[key] = &user
		}
	}
	return nil, sysUserMap
}

//@author: [q.zhangr](https://github.com/zqlove001)
//@function: SetRedisJWT
//@description: uuid存入redis并设置过期时间
//@param: uuid string
//@return: err error, redisJWT string
func SetRedisJWT(uuid uuid.UUID, user model.SysUser) (err error) {
	// 此处过期时间等于uuid过期时间
	//timer := time.Duration(global.GVA_CONFIG.JWT.ExpiresTime) * time.Second
	data, _ := json.Marshal(user)
	key := uuid.String()
	err = global.GVA_REDIS.HSet("guns:all:users", key, data).Err()
	return err
}

func DelRedisJWT(uuid uuid.UUID) (err error) {
	key := uuid.String()
	err = global.GVA_REDIS.HDel("guns:all:users", key).Err()
	return err
}

func DelRedisJWTWithString(gUuid string) (err error) {
	err = global.GVA_REDIS.HDel("guns:all:users", gUuid).Err()
	return err
}

func GenSysLoginUser(userId int, c *gin.Context) (err error, loginUser *response.SysLoginUser) {

	err, sysUser := QueryUserById(userId)

	if err != nil {
		return err, nil
	}

	sysLoginUser := new(response.SysLoginUser)

	err = utils.SimpleCopyProperties(sysLoginUser, sysUser)
	sysLoginUser.Id = sysUser.Id

	if err != nil {
		return err, nil
	}

	sysLoginUser.LastLoginIp = c.ClientIP()
	sysLoginUser.LastLoginTime = time.Now().String()
	//sysLoginUser.LastLoginAddress =
	//sysLoginUser.LastLoginBrowser =
	//sysLoginUser.LastLoginOs =

	// 员工信息
	err, loginEmpInfo := QuerySysEmpById(userId, false)
	sysLoginUser.LoginEmpInfo = *loginEmpInfo

	// 角色信息
	err, userRoleInfo := GetLoginRoles(userId)
	sysLoginUser.Roles = userRoleInfo

	// 权限信息
	err, permissions := GetLoginPermissions(userId)
	sysLoginUser.Permissions = permissions

	// 数据范围信息
	if loginEmpInfo.OrgId != nil {
		err, scopeIds := GetUserDataScopes(userId, *loginEmpInfo.OrgId)
		if err != nil {
			return err, nil
		}
		sysLoginUser.DataScopes = scopeIds
	} else {
		sysLoginUser.DataScopes = make([]int, 0)
	}

	// 具备应用信息（多系统，默认激活一个，可根据系统切换菜单）,返回的结果中第一个为激活的系统
	err, apps := GetLoginApps(userId)
	sysLoginUser.Apps = apps

	// 如果根本没有应用信息，则没有菜单信息
	if len(apps) <= 0 {
		sysLoginUser.Menus = make([]*response.LoginMenuTreeNode, 0)
	} else {
		defaultActiveAppCodeInterface := apps[0][global.CODE]
		defaultActiveAppCode, ok := defaultActiveAppCodeInterface.(string)

		if ok {
			err, menus := GetLoginMenusAntDesign(userId, defaultActiveAppCode)
			if err != nil {
				return err, nil
			}
			sysLoginUser.Menus = menus
		}
	}

	//设置权限相关
	sysLoginUser.AccountNonExpired = true
	sysLoginUser.AccountNonLocked = true
	sysLoginUser.CredentialsNonExpired = true
	sysLoginUser.Enabled = true
	sysLoginUser.Username = sysLoginUser.Account

	gunsAuthoritySlice := make([]*response.GunsAuthority, 0)

	if len(sysLoginUser.Roles) > 0 {

		for _, role := range sysLoginUser.Roles {
			gunsAuthority := new(response.GunsAuthority)
			roleName := role[global.NAME]
			gunsAuthority.Authority = roleName.(string)
			gunsAuthoritySlice = append(gunsAuthoritySlice, gunsAuthority)
		}
	}

	sysLoginUser.Authorities = gunsAuthoritySlice

	return err, sysLoginUser
}

func UserPage(param *request.SysUserParam, c *gin.Context) (err error, result *response.PageResult) {

	//根据关键字模糊查询（姓名，账号，手机号）
	var r []*response.SysUserResponse
	table := global.GVA_DB.Select("sys_user.*,sys_emp.job_num, sys_emp.org_id,sys_emp.org_name").
		Table("sys_user").
		Joins("left join sys_emp on sys_user.id = sys_emp.id").
		Joins("left join sys_org on sys_emp.org_id = sys_org.id")

	if param != nil {
		if param.SearchValue != "" {
			table = table.Where("(sys_user.account like ?", "%"+param.SearchValue+"%").
				Or("sys_user.name like ?", "%"+param.SearchValue+"%").
				Or("sys_user.phone like ?)", "%"+param.SearchValue+"%")
		}

		//根据员工所属机构查询
		sysEmpParam := param.SysEmpParam
		if sysEmpParam.OrgId != 0 {
			table = table.Where("(sys_emp.org_id = ?", sysEmpParam.OrgId).
				Or("sys_org.pids like ?)", "%"+strconv.Itoa(sysEmpParam.OrgId)+"%")
		}

		//根据状态查询（0正常 1停用），删除的不会展示在列表
		if param.SearchStatus != nil {
			table = table.Where("sys_user.status = ?", param.SearchStatus)
		}

		table = table.Where("sys_user.status <> ?", 2).Where("sys_user.admin_type <> ?", 1)

		//如果是超级管理员则获取所有用户，否则只获取其数据范围的用户
		err, superAdmin := IsSuperAdmin(c)

		if err != nil {
			return err, nil
		}

		if !superAdmin {
			dataScope := param.DataScope

			if len(dataScope) <= 0 {
				return err, nil
			} else {
				dataScopeSet := make([]int, 0)
				dataScopeSet = append(dataScopeSet, dataScope...)
				table = table.Where("sys_emp.org_id in (?)", dataScopeSet)
			}
		}

		var totalCount int64

		err = table.Count(&totalCount).Error

		if err != nil {
			return err, nil
		}

		pageNo, pageSize, table := utils.DefaultPage(c, table)

		err = table.Scan(&r).Error

		if err != nil {
			return err, nil
		}

		userResultSlice := make([]*response.SysUserResult, 0)

		for _, userResult := range r {

			u := new(response.SysUserResult)

			err = utils.SimpleCopyProperties(u, userResult)
			if err != nil {
				return err, nil
			}

			u.SysEmpInfo.OrgId = &(userResult.OrgId)
			u.SysEmpInfo.JobNum = &(userResult.JobNum)
			u.SysEmpInfo.OrgName = &(userResult.OrgName)

			userResultSlice = append(userResultSlice, u)
		}

		return err, utils.CoverToPageResult(pageNo, pageSize, totalCount, userResultSlice)
	}
	return err, nil
}

func UserDetail(sysUserParam request.SysUserParam) (err error, r *response.SysUserResult) {

	//获取系统用户
	err, sysUser := QueryUserById(sysUserParam.Id)

	sysUserResult := new(response.SysUserResult)

	err = utils.SimpleCopyProperties(sysUserResult, &sysUser)

	if err != nil {
		return err, nil
	}

	//获取对应员工信息
	err, LoginEmpInfo := QuerySysEmpById(sysUser.Id, true)

	if err != nil {
		return err, nil
	}

	sysEmpInfo := new(response.SysEmpInfo)

	err = utils.SimpleCopyProperties(sysEmpInfo, LoginEmpInfo)

	if err != nil {
		return err, nil
	}

	//设置员工信息
	sysUserResult.SysEmpInfo = *sysEmpInfo

	return err, sysUserResult
}

func ResetPwd(sysUserParam *request.SysUserParam) error {

	err, sysUser := QueryUserById(sysUserParam.Id)

	if err != nil {
		return err
	}

	//TODO 配置方式
	//设置初始密码
	password := "123456"
	password = utils.MD5V([]byte(password))

	tx := global.GVA_DB.Begin()

	err = tx.Model(&sysUser).Update("password", password).Error

	if err != nil {
		tx.Rollback()
		return err
	}
	tx.Commit()
	return nil
}

func OwnRole(sysUserParam *request.SysUserParam) (err error, roles []int) {

	err, sysUser := QueryUserById(sysUserParam.Id)

	if err != nil {
		return err, nil
	}

	err, roleIds := GetUserRoleIdList(sysUser.Id)

	if err != nil {
		return err, nil
	}

	return err, roleIds
}

func OwnData(sysUserParam *request.SysUserParam) (err error, roles []int) {

	if sysUserParam != nil {

		err, sysUser := QueryUserById(sysUserParam.Id)

		if err != nil {
			return err, nil
		}

		err, scopeIds := GetUserDataScopeIdSlice(sysUser.Id)

		return err, scopeIds
	}
	return err, nil
}

func UserDelete(sysUserParam *request.SysUserParam, c *gin.Context) error {

	if sysUserParam != nil {

		err, sysUser := QueryUserById(sysUserParam.Id)

		if err != nil {
			return err
		}

		//不能删除超级管理员
		if sysUser.AdminType == global.SuperAdmin {
			return errors.New("不能删除超级管理员")
		}

		err, superAdmin := IsSuperAdmin(c)

		if err != nil {
			return err
		}

		//如果登录用户不是超级管理员，则进行数据权限校验
		if !superAdmin {

			dataScopes := sysUserParam.DataScope
			//获取要删除的用户的所属机构
			err, sysEmpInfo := QuerySysEmpById(sysUser.Id, true)

			if err != nil {
				return err
			}

			orgId := sysEmpInfo.OrgId
			isContain, _ := utils.Contain(orgId, dataScopes)

			//数据范围为空
			if len(dataScopes) < 0 {
				return errors.New("没有权限操作该数据，请联系管理员")
			} else if !isContain {
				//所要删除的用户的所属机构不在自己的数据范围内
				return errors.New("没有权限操作该数据，请联系管理员")
			}
		}

		tx := global.GVA_DB.Begin()

		//更新用户为删除状态
		err = tx.Model(&sysUser).Update("status", 2).Error

		if err != nil {
			tx.Rollback()
			return err
		}

		userId := sysUser.Id

		//删除该用户对应的员工表信息
		err = DeleteEmpInfoByUserId(userId, tx)

		if err != nil {
			tx.Rollback()
			return err
		}

		//删除该用户对应的用户-角色表关联信息
		err = DeleteUserRoleListByUserId(userId, tx)

		if err != nil {
			tx.Rollback()
			return err
		}

		//删除该用户对应的用户-数据范围表关联信息
		err = DeleteUserDataScopeListByUserId(userId, tx)

		if err != nil {
			tx.Rollback()
			return err
		}

		tx.Commit()
	}

	return nil
}

func UserAdd(sysUserParam *request.SysUserParam, c *gin.Context) error {

	err := checkParam(sysUserParam, false)

	if err != nil {
		return err
	}

	err, superAdmin := IsSuperAdmin(c)

	if err != nil {
		return err
	}

	if !superAdmin {

		dataScopes := sysUserParam.DataScope
		//获取要删除的用户的所属机构
		orgId := sysUserParam.SysEmpParam.OrgId
		isContain, _ := utils.Contain(orgId, dataScopes)

		//数据范围为空
		if len(dataScopes) < 0 {
			return errors.New("没有权限操作该数据，请联系管理员")
		} else if !isContain {
			//所要删除的用户的所属机构不在自己的数据范围内
			return errors.New("没有权限操作该数据，请联系管理员")
		}
	}

	sysUser := new(model.SysUser)

	err = utils.SimpleCopyProperties(sysUser, sysUserParam)

	if err != nil {
		return err
	}

	FillAddCommonUserInfo(sysUser)

	//设置生日
	birthday, _ := time.Parse("2006-01-02", sysUserParam.Birthday)
	sysUser.Birthday = birthday

	tx := global.GVA_DB.Begin()

	err = SaveUser(sysUser, tx)

	if err != nil {
		tx.Rollback()
		return err
	}

	userId := sysUser.Id
	//增加员工信息
	sysEmpParam := sysUserParam.SysEmpParam

	sysEmpParam.Id = userId

	err = EmpAddOrUpdate(sysEmpParam, tx)

	if err != nil {
		tx.Rollback()
		return err
	}
	tx.Commit()
	return nil
}

func UserEdit(sysUserParam *request.SysUserParam, c *gin.Context) error {

	err, user := QueryUserById(sysUserParam.Id)

	err = checkParam(sysUserParam, true)

	if err != nil {
		return err
	}

	err, superAdmin := IsSuperAdmin(c)

	if err != nil {
		return err
	}

	if !superAdmin {

		dataScopes := sysUserParam.DataScope
		//获取要删除的用户的所属机构
		orgId := sysUserParam.SysEmpParam.OrgId
		isContain, _ := utils.Contain(orgId, dataScopes)

		//数据范围为空
		if len(dataScopes) < 0 {
			return errors.New("没有权限操作该数据，请联系管理员")
		} else if !isContain {
			//所要删除的用户的所属机构不在自己的数据范围内
			return errors.New("没有权限操作该数据，请联系管理员")
		}
	}

	sysUser := &user

	err = utils.SimpleCopyProperties(sysUser, sysUserParam)

	if err != nil {
		return err
	}

	//不能修改状态，用修改状态接口修改状态
	sysUser.Status = 0

	FillAddCommonUserInfo(sysUser)

	tx := global.GVA_DB.Begin()

	err = UpdateUserById(sysUser, tx)

	if err != nil {
		tx.Rollback()
		return err
	}

	userId := sysUser.Id
	//编辑员工信息
	sysEmpParam := sysUserParam.SysEmpParam

	err = utils.SimpleCopyProperties(sysEmpParam, sysUserParam)

	sysEmpParam.Id = userId

	err = EmpAddOrUpdate(sysEmpParam, tx)

	if err != nil {
		tx.Rollback()
		return err
	}
	tx.Commit()
	return nil
}

func UserGrantRole(sysUserParam *request.SysUserParam, c *gin.Context) error {

	err, user := QueryUserById(sysUserParam.Id)

	if err != nil {
		return err
	}

	err, superAdmin := IsSuperAdmin(c)

	if err != nil {
		return err
	}

	//如果登录用户不是超级管理员，则进行数据权限校验
	if !superAdmin {
		dataScopes := sysUserParam.DataScope
		//获取要授权角色的用户的所属机构
		err, sysEmpInfo := QuerySysEmpById(user.Id, true)

		if err != nil {
			return err
		}

		orgId := sysEmpInfo.OrgId
		isContain, _ := utils.Contain(orgId, dataScopes)

		//数据范围为空
		if len(dataScopes) < 0 {
			return errors.New("没有权限操作该数据，请联系管理员")
		} else if !isContain {
			//所要授权角色的用户的所属机构不在自己的数据范围内
			return errors.New("没有权限操作该数据，请联系管理员")
		}
	}

	return SysUserGrantRole(sysUserParam)
}

func UserGrantData(sysUserParam *request.SysUserParam, c *gin.Context) error {

	err, user := QueryUserById(sysUserParam.Id)

	if err != nil {
		return err
	}

	err, superAdmin := IsSuperAdmin(c)

	if err != nil {
		return err
	}

	//如果登录用户不是超级管理员，则进行数据权限校验
	if !superAdmin {
		dataScopes := sysUserParam.DataScope
		//获取要授权角色的用户的所属机构
		err, sysEmpInfo := QuerySysEmpById(user.Id, true)

		if err != nil {
			return err
		}

		orgId := sysEmpInfo.OrgId
		isContain, _ := utils.Contain(orgId, dataScopes)

		//数据范围为空
		if len(dataScopes) < 0 {
			return errors.New("没有权限操作该数据，请联系管理员")
		} else if !isContain {
			//所要授权角色的用户的所属机构不在自己的数据范围内
			return errors.New("没有权限操作该数据，请联系管理员")
		}
	}

	return SysUserGrantData(sysUserParam)
}

func FillAddCommonUserInfo(sysUser *model.SysUser) {

	fillBaseUserInfo(sysUser)
	sysUser.AdminType = 2
}

func fillBaseUserInfo(sysUser *model.SysUser) {

	//密码为空则设置密码
	if sysUser.Password == "" {
		//没有密码则设置默认密码
		password := "12456"
		//设置密码为Md5加密后的密码
		sysUser.Password = utils.MD5V([]byte(password))
	}

	if sysUser.Avatar == nil {
		sysUser.Avatar = nil
	}

	if sysUser.Sex == nil {
		sex := int8(3)
		sysUser.Sex = &sex
	}
}

func checkParam(sysUserParam *request.SysUserParam, isExcludeSelf bool) error {

	userId := sysUserParam.Id

	account := sysUserParam.Account

	var user model.SysUser
	db := global.GVA_DB.Where("account = ?", account).Where("status <> ?", 2)

	if isExcludeSelf {
		db = db.Where("id <> ?", userId)
	}

	var countByAccount int64

	err := db.Find(&user).Count(&countByAccount).Error

	if err != nil {
		return err
	}

	if countByAccount >= 1 {
		return errors.New("账号已存在，请检查account参数")
	}

	return nil
}

func ChangeStatus(sysUserParam *request.SysUserParam) error {

	err, user := QueryUserById(sysUserParam.Id)

	if err != nil {
		return err
	}
	//不能修改超级管理员状态
	if user.AdminType == global.SuperAdmin {
		return errors.New("不能修改超级管理员状态")
	}

	status := sysUserParam.Status

	err = utils.ValidateStatus(status)

	if err != nil {
		return err
	}

	tx := global.GVA_DB.Begin()

	//更新枚举，更新只能更新未删除状态的
	err = tx.Model(&user).Where("status <> ?", 2).Update("status", status).Error

	if err != nil {
		tx.Rollback()
		return errors.New(err.Error() + "更新状态失败，您试图更新被删除的记录")
	}

	tx.Commit()
	return nil
}

func UpdateUserInfo(sysUserParam *request.SysUserParam) error {

	err, user := QueryUserById(sysUserParam.Id)

	if err != nil {
		return err
	}

	err = utils.SimpleCopyProperties(&user, sysUserParam)

	if err != nil {
		return err
	}

	birthday, _ := time.Parse("2006-01-02", sysUserParam.Birthday)

	updateUser := model.SysUser{
		NickName: sysUserParam.NickName,
		Birthday: birthday,
		Sex:      sysUserParam.Sex,
		Phone:    sysUserParam.Phone,
		Tel:      sysUserParam.Tel,
		Email:    sysUserParam.Email,
	}

	tx := global.GVA_DB.Begin()

	err = tx.Model(model.SysUser{}).Where("id =  ?", user.Id).Updates(&updateUser).Error

	if err != nil {
		tx.Rollback()
		return err
	}

	tx.Commit()
	return nil
}

func UpdatePwd(sysUserParam *request.SysUserParam) error {

	err, user := QueryUserById(sysUserParam.Id)

	if err != nil {
		return err
	}

	//新密码与原密码相同
	if *sysUserParam.Password == sysUserParam.NewPassword {
		return errors.New("新密码与原密码相同，请检查newPassword参数")
	}

	newPassword := utils.MD5V([]byte(*sysUserParam.Password))

	if user.Password != newPassword {
		return errors.New("原密码错误，请检查password参数")
	}

	storePassword := utils.MD5V([]byte(sysUserParam.NewPassword))

	tx := global.GVA_DB.Begin()

	err = tx.Model(&user).Update("password", storePassword).Error

	if err != nil {
		tx.Rollback()
		return err
	}

	tx.Commit()
	return nil
}

func UpdateAvatar(sysUserParam *request.SysUserParam) error {

	err, user := QueryUserById(sysUserParam.Id)

	if err != nil {
		return err
	}

	avatar := sysUserParam.Avatar

	err = AssertFile(avatar)

	if err != nil {
		return err
	}

	tx := global.GVA_DB.Begin()

	err = tx.Model(&user).Update("avatar", avatar).Error

	if err != nil {
		tx.Rollback()
		return err
	}

	tx.Commit()
	return nil
}

func Selector(sysUserParam *request.SysUserParam) (error, []map[string]interface{}) {

	dictSlice := make([]map[string]interface{}, 0)

	var sysUserSlice []*model.SysUser
	db := global.GVA_DB

	if sysUserParam != nil {
		//根据姓名模糊查询
		if sysUserParam.Name != "" {
			db = db.Where("name like ?", "%"+sysUserParam.Name+"%")
		}
	}

	//查询非删除状态，排除超级管理员
	db = db.Where("status <> ?", 2).Where("admin_type <> ?", global.SuperAdmin)

	err := db.Find(&sysUserSlice).Error

	if err != nil {
		return err, nil
	}

	if len(sysUserSlice) > 0 {

		for _, sysUser := range sysUserSlice {

			dict := make(map[string]interface{}, 0)
			dict[global.ID] = strconv.Itoa(sysUser.Id)
			dict[global.NAME] = sysUser.Name

			dictSlice = append(dictSlice, dict)
		}
	}
	return nil, dictSlice
}
